home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 5 / Apprentice-Release5.iso / Source Code / PowerPlant / CDLOGMenuBar / CDLOGMenuBar.cp next >
Encoding:
Text File  |  1996-04-02  |  14.0 KB  |  436 lines  |  [TEXT/CWIE]

  1. /************************************************************************
  2. *****    File : CDLOGMenuBar.cp                                        *****
  3. *****    Copyright 1996, Thomas R. Kimpton                            *****
  4. *****        All Rights Reserved                                        *****
  5. *****                                                                *****
  6. *****    This source code may be freely used in any programming        *****
  7. *****    project so long as credit is duly noted of the author.        *****
  8. ************************************************************************/
  9.     
  10.         
  11. //************************************************************************
  12. #pragma mark    standard header files
  13. //************************************************************************
  14. #include <StdIO.h>
  15. #include <String.h>
  16.  
  17. //************************************************************************
  18. #pragma mark    local header files
  19. //************************************************************************
  20. #include "CDLOGMenuBar.h"
  21. #include "Utilities.h"
  22.  
  23. //************************************************************************
  24. #pragma mark    constant definitions
  25. //************************************************************************
  26.  
  27. //************************************************************************
  28. #pragma mark    macro definitions
  29. //************************************************************************
  30.  
  31. //************************************************************************
  32. #pragma mark    type definitions
  33. //************************************************************************
  34.  
  35. //************************************************************************
  36. #pragma mark    class definitions
  37. //************************************************************************
  38.  
  39. //************************************************************************
  40. #pragma mark    static variables
  41. //************************************************************************
  42. // These static variables are set just before using the MenuHookProc
  43. static Rect                smMBARRect;        // Rect, in window, that comprises the menubar.
  44. static short            smCurMenu;        // Index into mMenus for menu currently displayed.
  45. static auxMenuStruct    *smMenus;        // Holds the handle and titleRect(within the MBAR) for each menu.
  46. static Point            sUpperLeft;        // Used to do a GlobalToLocal() when it's not feasible to make the call...
  47.  
  48. //************************************************************************
  49. #pragma mark    global variables
  50. //************************************************************************
  51.  
  52. //************************************************************************
  53. #pragma mark    forward declarations (prototypes)
  54. //************************************************************************
  55.  
  56. //************************************************************************
  57. #pragma mark    external variables
  58. //************************************************************************
  59.  
  60. //************************************************************************
  61. #pragma mark    external functions
  62. //************************************************************************
  63.  
  64. /************************************************************************
  65. *****                                                                *****
  66. ************************************************************************/
  67.  
  68. /************************************************************************
  69. *****    Return a new Pane object initialized using data from        *****
  70. *****    a Stream (PPOB object).                                        *****
  71. ************************************************************************/
  72. CDLOGMenuBar*
  73. CDLOGMenuBar::CreatePaneStream( LStream    *inStream)
  74. {
  75.     return (new CDLOGMenuBar(inStream));
  76. }
  77.  
  78.  
  79. /************************************************************************
  80. *****    Default Constructor                                            *****
  81. ************************************************************************/
  82. CDLOGMenuBar::CDLOGMenuBar()
  83. {
  84.  
  85. short menuBarWidth = 0;
  86. short numMenus;
  87. short *menuIDPtr;
  88. register short i;
  89. MenuHandle theMenuHndl;
  90. short menuBoundsPtr;
  91. Handle theMenuBar;
  92. unsigned char oldState;
  93. Rect    theFrame;
  94.  
  95.     CalcLocalFrameRect(theFrame);
  96.  
  97.     // Set the mUserCon in Constructor...
  98.     theMenuBar = GetResource(kMBARrsrcType,mUserCon);
  99.     if(!theMenuBar)
  100.         throw;
  101.  
  102.     oldState = HLockState((Handle)theMenuBar);
  103.  
  104.     numMenus = *(short *)*theMenuBar;
  105.     numMenus = (numMenus > kNumMbarMenus) ? kNumMbarMenus : numMenus;
  106.     mNumMenus = numMenus;
  107.  
  108.     menuIDPtr = (short *)*theMenuBar;
  109.     menuIDPtr++;    /* Skip over the number of menus. */
  110.     menuBoundsPtr = theFrame.left;
  111.  
  112.     for(i = 0; i < numMenus; i++,menuIDPtr++){
  113.         theMenuHndl = GetMenu(*menuIDPtr);
  114.         mMenus[i].theMenu = theMenuHndl;
  115.         mMenus[i].titleRect.top = theFrame.top;
  116.         mMenus[i].titleRect.bottom = theFrame.bottom;
  117.         mMenus[i].titleRect.left = menuBoundsPtr;
  118.         menuBoundsPtr += StringWidth((ConstStr255Param) (**theMenuHndl).menuData) + 2 * kMenuHMargin;
  119.         mMenus[i].titleRect.right = menuBoundsPtr;
  120.     }
  121.  
  122.     mMBARRect = theFrame;
  123.  
  124.     mCurMenu = -1;
  125.  
  126.     HSetState(theMenuBar,oldState);
  127.     ReleaseResource(theMenuBar);
  128.  
  129.     mMenuHook = NewMenuHookProc(MenuHookProc);
  130. }
  131.  
  132.  
  133. /************************************************************************
  134. *****    Copy Constructor (not tested)                                *****
  135. ************************************************************************/
  136. CDLOGMenuBar::CDLOGMenuBar(const CDLOGMenuBar    &inOriginal)
  137. {
  138.                                     // Copy members of Original
  139.     mMenuHook = inOriginal.mMenuHook;
  140. }
  141.  
  142. /************************************************************************
  143. *****    Construct Pane from data in a Stream (PPOB object)            *****
  144. ************************************************************************/
  145. CDLOGMenuBar::CDLOGMenuBar( LStream    * inStream ) : LPane(inStream)
  146. {
  147. short menuBarWidth = 0;
  148. short numMenus;
  149. short *menuIDPtr;
  150. register short i;
  151. MenuHandle theMenuHndl;
  152. short menuBoundsPtr;
  153. Handle theMenuBar;
  154. unsigned char oldState;
  155. Rect    theFrame;
  156. StTextState    saveTextState;        // Will save and restore text state
  157.  
  158.     // Set the mUserCon in Constructor...
  159.     theMenuBar = GetResource(kMBARrsrcType,mUserCon);
  160.     if(!theMenuBar)
  161.         throw;
  162.  
  163.     mCurMaxNumMbarMenus = kNumMbarMenus;
  164.     mMenus = (auxMenuStruct *)NewPtrClear(mCurMaxNumMbarMenus * sizeof(auxMenuStruct    *));
  165.     if(!mMenus || (MemError() != noErr)){
  166.         throw;
  167.     }
  168.     TextFont(systemFont);
  169.     TextSize(0);
  170.  
  171.     mTheSelection = 0;
  172.     mMenuHook = nil;
  173.     mNumMenus = 0;
  174.     mCurMenu = -1;
  175.     CalcLocalFrameRect(theFrame);
  176.  
  177.     oldState = HLockState(theMenuBar);
  178.  
  179.     numMenus = *(short *)*theMenuBar;
  180.     numMenus = (numMenus > kNumMbarMenus) ? kNumMbarMenus : numMenus;
  181.     mNumMenus = numMenus;
  182.  
  183.     menuIDPtr = (short *)*theMenuBar;
  184.     menuIDPtr++;    /* Skip over the number of menus. */
  185.     menuBoundsPtr = theFrame.left;
  186.  
  187.     for(i = 0; i < numMenus; i++,menuIDPtr++){
  188.         theMenuHndl = GetMenu(*menuIDPtr);
  189.         mMenus[i].theMenu = theMenuHndl;
  190.         mMenus[i].titleRect.top = theFrame.top;
  191.         mMenus[i].titleRect.bottom = theFrame.bottom;
  192.         mMenus[i].titleRect.left = menuBoundsPtr;
  193.         menuBoundsPtr += StringWidth((ConstStr255Param) (**theMenuHndl).menuData) + 2 * kMenuHMargin;
  194.         mMenus[i].titleRect.right = menuBoundsPtr;
  195.     }
  196.  
  197.     mMBARRect = theFrame;
  198.  
  199.     mCurMenu = -1;
  200.  
  201.     HSetState(theMenuBar,oldState);
  202.     ReleaseResource(theMenuBar);
  203.  
  204.     mMenuHook = NewMenuHookProc(MenuHookProc);
  205. }
  206.  
  207.  
  208. /************************************************************************
  209. *****    Destructor                                                    *****
  210. ************************************************************************/
  211. CDLOGMenuBar::~CDLOGMenuBar()
  212. {
  213. register short i;
  214.  
  215.     for(i=0;i<mNumMenus;i++){
  216.         if(mMenus[i].theMenu)
  217.             ReleaseResource((Handle)mMenus[i].theMenu);
  218.     }
  219.     if(mMenus)
  220.         DisposePtr((Ptr)mMenus);
  221.     if(mMenuHook)
  222.         DisposeRoutineDescriptor(mMenuHook);
  223. }
  224.  
  225. /************************************************************************
  226. *****    Handle MouseDown in DLOGMenuBar.                            *****
  227. ************************************************************************/
  228. void
  229. CDLOGMenuBar::ClickSelf( const SMouseDownEvent&    /* inMouseDown */ )
  230. {
  231. Point    hitPt;
  232. MenuHandle theMenu;
  233. Rect tmpTitleRect;
  234. Rect titleInvertRect;
  235. UniversalProcPtr OldMenuHook;
  236. short i;
  237. Point loc;
  238. Rect    theFrame;
  239.  
  240.     CalcLocalFrameRect(theFrame);
  241.  
  242.     mTheSelection = 0;
  243.  
  244. // These static variables are set just before using the MenuHookProc.
  245. // We have to use static variables, because the MenuHookProc can't access
  246. // instance variables.
  247.     smMBARRect = mMBARRect;            // Rect, in window, that comprises the menubar.
  248.     smMenus = &mMenus[0];            // Holds the handle and titleRect(within the MBAR) for each menu.
  249.     sUpperLeft.v = theFrame.top;
  250.     sUpperLeft.h = theFrame.left;
  251.     LocalToGlobal(&sUpperLeft);
  252.  
  253.     OldMenuHook = LMGetMenuHook();
  254.     LMSetMenuHook((UniversalProcPtr)mMenuHook);
  255.  
  256.     /* A mouseDown in our "menubar" got us into this routine.
  257.      * The routine MenuHookProc() watches where the mouse is and
  258.      * posts a mouseUp event if we get into the menubar and we are
  259.      * not in this menu's title rect.  PopUpMenuSelect() looks for
  260.      * this mouseUp and returns. However, the mouse button may really
  261.      * still be down, so we see if we should popup another menu.
  262.      *
  263.      * Because this menubar can be in a movable window, it's possible
  264.      * that the menubar may be down near the bottom of the window, and
  265.      * the menu won't popup(down).  So we add code to check to see if
  266.      * the menu will fit on the window.  If it won't, we pop the menu
  267.      * UP above the menubar.  BUT if the menu is taller than the device
  268.      * AND the menu's in the top half of the screen, we pop it down. phew!
  269.      */
  270.     while(Button()){
  271.         GetMouse(&hitPt);
  272.         for(i = 0; i < mNumMenus; i++){
  273.             tmpTitleRect = mMenus[i].titleRect;
  274.             if(PtInRect(hitPt,&tmpTitleRect)){
  275.             Rect thePortRect;
  276.             short tmpSelection;
  277.  
  278.                 mCurMenu = i;
  279.                 smCurMenu = mCurMenu;            // Index into mMenus for menu currently displayed.
  280.                 titleInvertRect = tmpTitleRect;
  281.                 InvertRect(&titleInvertRect);
  282.  
  283.                 theMenu = mMenus[i].theMenu;
  284.                 InsertMenu(theMenu, hierMenu);
  285.                 CalcMenuSize(theMenu);        /* Is this still necessary? */
  286.                     /* Increment them so the menu frame gets drawn correctly */
  287.                 loc.h = tmpTitleRect.left + 1;
  288.                 loc.v = tmpTitleRect.bottom + 1;
  289.                 LocalToGlobal(&loc);
  290.                 GetPortRectForThisPoint(loc,&thePortRect);
  291.                 if((loc.v + (**theMenu).menuHeight) > thePortRect.bottom){
  292.                 short portHeight = thePortRect.bottom - thePortRect.top;
  293.                     if(((**theMenu).menuHeight > (portHeight)) && 
  294.                       loc.v < (thePortRect.top + portHeight/2)){ // Is the menu taller than the screen, and 
  295.                                                                    // we're in the top half of the window?
  296.                         tmpSelection = 0;
  297.                     }
  298.                     else{
  299.                         loc.h = tmpTitleRect.left + 1;
  300.                         loc.v = tmpTitleRect.top - 1;
  301.                         tmpSelection = 0x7fff;
  302.                         LocalToGlobal(&loc);
  303.                     }
  304.                 }
  305.                 else
  306.                     tmpSelection = 0;
  307.                 mTheSelection = PopUpMenuSelect(theMenu, loc.v, loc.h, tmpSelection);
  308.                 DeleteMenu((**theMenu).menuID);
  309.                 InvertRect(&titleInvertRect);
  310.                 break;
  311.             }    /* PtInRect */
  312.         }    /* for */
  313.     }    /* while() */
  314.  
  315.     LMSetMenuHook(OldMenuHook);
  316.     if(mTheSelection != 0)
  317.         BroadcastMessage(msg_DLOGMenuBarSelection,(void *)mTheSelection);
  318. }
  319.  
  320. /************************************************************************
  321. *****    Draw the menubar.                                            *****
  322. ************************************************************************/
  323. void
  324. CDLOGMenuBar::DrawSelf()
  325. {
  326. register short i;
  327. MenuHandle theMenu;
  328. StTextState    saveTextState;        // Will save and restore text state
  329.  
  330.     TextFont(systemFont);
  331.     TextSize(0);
  332.     RGBColor bgColor = {0xffff,0xffff,0xffff};
  333.     RGBColor fgColor = {0,0,0};
  334.     RGBColor oldbgColor;
  335.     RGBColor oldfgColor;
  336.     GetBackColor(&oldbgColor);
  337.     GetForeColor(&oldfgColor);
  338.  
  339.     RGBForeColor (&fgColor);
  340.     RGBBackColor (&bgColor);
  341.     EraseRect(&mMBARRect);
  342.  
  343.     for(i = 0; i < mNumMenus; i++){
  344.         theMenu = mMenus[i].theMenu;
  345.         ::TETextBox((ConstStr255Param) &(((**theMenu).menuData)[1]),
  346.             (long)(((**theMenu).menuData)[0]),
  347.             &mMenus[i].titleRect,teJustCenter);
  348.     }
  349.     MoveTo((short) mMBARRect.left,(short) mMBARRect.bottom);
  350.     LineTo((short) mMBARRect.right,(short) mMBARRect.bottom);
  351.  
  352.     RGBForeColor (&oldfgColor);
  353.     RGBBackColor (&oldbgColor);
  354. }
  355.  
  356. /************************************************************************
  357. *****    To emulate a menubar we need to post a mouseUp event if        *****
  358. *****    the cursor enters the menubar, but is no longer in the        *****
  359. *****    title rect of the 'current' menu. PopupMenuSelect() watches    *****
  360. *****    for a mouseUp event to tell it to 'collapse' the menu.        *****
  361. ************************************************************************/
  362. pascal void
  363. CDLOGMenuBar::MenuHookProc(void)
  364. {
  365. Point curPoint;
  366. short workAround;
  367.  
  368.     GetMouse(&curPoint);
  369.     curPoint.h -= sUpperLeft.h;
  370.     curPoint.v -= sUpperLeft.v;
  371.     workAround = 1;    // Had to put this in (for CW) because curPoint was getting munged...???
  372.  
  373.     if(PtInRect(curPoint,&smMBARRect)){
  374.         if(!PtInRect(curPoint,&smMenus[smCurMenu].titleRect)){
  375.             PostEvent(mouseUp,0);
  376.         }
  377.     }
  378. }
  379.  
  380. /************************************************************************
  381. *****    Add a menu to the end of the menubar.                        *****
  382. ************************************************************************/
  383. OSErr
  384. CDLOGMenuBar::insertMenuDlogMenuBar(MenuHandle theMenu,short *whichMenuIndex)
  385. {
  386. Rect frameRect;
  387. short whichMenu;
  388. short menuBoundsPtr;
  389.  
  390.     mNumMenus++;
  391.     if(mNumMenus >= (mCurMaxNumMbarMenus - 1)){
  392.     auxMenuStruct    *tmpMenus;
  393.         mCurMaxNumMbarMenus += kMbarMenusIncr;
  394.         // Doing it this way is less likely to fail than doing a SetPtrSize().
  395.         tmpMenus = (auxMenuStruct *)NewPtrClear(mCurMaxNumMbarMenus * sizeof(auxMenuStruct    *));
  396.         if(!tmpMenus || (MemError() != noErr)){
  397.             mCurMaxNumMbarMenus -= kMbarMenusIncr;
  398.             --mNumMenus;
  399.             return(MemError());
  400.         }
  401.         memcpy(tmpMenus,mMenus,(mNumMenus - 1) * sizeof(auxMenuStruct    *));
  402.         DisposePtr((Ptr)mMenus);
  403.         mMenus = tmpMenus;
  404.     }
  405.     CalcLocalFrameRect(frameRect);
  406.  
  407.  
  408.     menuBoundsPtr = frameRect.right;
  409.  
  410.     whichMenu = mNumMenus - 1;
  411.     mMenus[whichMenu].theMenu = theMenu;
  412.     mMenus[whichMenu].titleRect.top = frameRect.top;
  413.     mMenus[whichMenu].titleRect.bottom = frameRect.bottom;
  414.     mMenus[whichMenu].titleRect.left = menuBoundsPtr;
  415.     menuBoundsPtr += StringWidth((ConstStr255Param) (**theMenu).menuData) + 2 * kMenuHMargin;
  416.     mMenus[whichMenu].titleRect.right = menuBoundsPtr;
  417.  
  418.     *whichMenuIndex = whichMenu;
  419.  
  420.     return(noErr);
  421. }
  422.  
  423. /************************************************************************
  424. *****    Return the menuHandle that corresponds to whichMenuIndex.    *****
  425. ************************************************************************/
  426. MenuHandle
  427. CDLOGMenuBar::getDlogMenuBarMenu(short whichMenuIndex)
  428. {
  429.  
  430.     if(whichMenuIndex > (mNumMenus - 1))
  431.         return(nil);
  432.     else
  433.         return(mMenus[whichMenuIndex].theMenu);
  434. }
  435.  
  436.